#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "wave_reader.h"

#include <cmath>
#include <memory>

constexpr uint32_t SAMPLE_RATE = 48000;
constexpr uint16_t CHANNEL_COUNT = 2;
constexpr uint16_t BIT_PER_SAMPLE = 16;

struct BufferWriter
{
    char* buf_;
    int pos_;
    int size_;

    BufferWriter(): buf_(nullptr), pos_(0), size_(0)
    {
    }

    BufferWriter(char* buf, int size): buf_(buf), pos_(0), size_(size)
    {
    }

    ~BufferWriter() 
    {
    }

    int Write(char* data, int len)
    {
        if(buf_ == nullptr) return 0;

        int nleft = size_ - pos_;
        int nwrite = nleft < len ? nleft : len;

        memcpy(buf_ + pos_, data, nwrite);
        pos_ += nwrite;

        return nwrite;
    }
};

// generate 400 hz sin, the period is 1000ms/400 = 2.5ms.
// there will be 48000/400 = 120 samples in one period.
// split 2pi as 120 samples
int GenerateSineWave(std::shared_ptr<char[]> &buffer, std::size_t &size)
{
    double scale; 
    int16_t basic_volume = 100;
    int16_t sample = 0;
    int samples_count = 120;
    int samples_buffer_size = samples_count * 2 * 2;

    size = samples_buffer_size;

    BufferWriter bw(new char[samples_buffer_size], samples_buffer_size);

    for(double i = 0; i < 120; i++) {
        scale = ::sin(2 * M_PI/(double)samples_count * i);
        sample = (uint16_t)((double)basic_volume * scale);
        bw.Write((char*)&sample, 2); // s16le, left channel
        bw.Write((char*)&sample, 2); // s16le, right channel
    }

    buffer.reset(bw.buf_);

    return 0;
}

TEST_CASE("test WaveReader is working correctly", "[WaveReader]") {
    WaveReader reader;

    REQUIRE(reader.Open("yes.minister.speech.wav") == 0);

    SECTION("check wether audio info correct") {
        uint32_t sample_rate;
        uint16_t channel_count; 
        uint16_t bit_per_sample;

        REQUIRE(reader.GetAudioInfo(sample_rate, channel_count, bit_per_sample) == 0);
        REQUIRE(sample_rate == 48000);
        REQUIRE(channel_count == 2);
        REQUIRE(bit_per_sample == 16);
    }
};

TEST_CASE("test WaveWriter is working correctly", "[WaveWriter]") {
    WaveWriter writer;

    REQUIRE(writer.Open("wave.writer.test.wav") == 0);

    uint32_t sample_rate = 48000;
    uint16_t channel_count = 2;
    uint16_t bit_per_sample = 16;

    REQUIRE(writer.SetAudioInfo(sample_rate, channel_count, bit_per_sample) == 0);

    std::shared_ptr<char[]> audio_buf;
    std::size_t audio_buf_size;
    int wave_freq = 400;
    int audio_length_second = 20; 
    GenerateSineWave(audio_buf, audio_buf_size);

    REQUIRE(writer.Write(audio_buf.get(), audio_buf_size, wave_freq * audio_length_second) == (wave_freq * audio_length_second));

    writer.Close();
};